<template>
  <div>
    <el-dialog
      v-model="visible"
      title="攻击路径"
      class="attack-path-dialog"
    >
      <div class="mx-1 relative">
        <el-button
            type="primary"
            @click="attackPathVisible = true"
            class="snapshot-button"
        >新建</el-button>
        <el-input
            v-model="keyword"
            placeholder="请输入搜索内容"
            clearable
            class="attack-path-search"
            @input="getAttackPathData"
        />
        <TableComponent
            ref="tableRef"
            :table-list="state.tableData"
            :table-column-info="attackPathList"
            :options-button="optionsButton"
            @updateData="setPageInfo"
            @defaultPageData="setDefaultPage"
            :options-width="140"
        >
          <template #path="{ data: { attackPathList } }">
            <div style="overflow: hidden; width: 100%; height: 100%" :title="attackPathShow(attackPathList)">
               <span v-for="(item, index) in attackPathList">
              <span v-text="item.name" />
              <el-icon style="vertical-align: middle; display: inline-block; margin: 0 6px;" v-if="index !== attackPathList?.length - 1"><Right /></el-icon>
            </span>
            </div>
          </template>
        </TableComponent>
        <div class="space-x-1 flex items-center absolute right-0 top-0" />

       <div>
         <el-dialog v-model="attackPathVisible" title="新建攻击路径" class="add-attack-dialog">
           <el-form
               ref="attackPathFormRef"
               :model="attackPathForm"
               :rules="attackPathRules"
               class="m-auto mt-1"
           >
             <el-form-item label="名称" prop="name">
               <el-input v-model="attackPathForm.name" />
             </el-form-item>
             <el-form-item label="开始节点" prop="sourceInstanceUUID">
               <el-select
                   v-model="attackPathForm.sourceInstanceUUID"
                   filterable
                   clearable
                   placeholder="请选择"
               >
                 <el-option
                     v-for="item in sceneInstanceList"
                     :key="item.id"
                     :label="item.name"
                     :value="item.id"
                 />
               </el-select>
             </el-form-item>
             <el-form-item label="结束节点" prop="targetInstanceUUID">
               <el-select
                   v-model="attackPathForm.targetInstanceUUID"
                   filterable
                   clearable
                   placeholder="请选择"
               >
                 <el-option
                     v-for="item in sceneInstanceList"
                     :key="item.id"
                     :label="item.name"
                     :value="item.id"
                 />
               </el-select>
             </el-form-item>
           </el-form>
           <template #footer>
        <span>
          <el-button @click="attackPathVisible = false">取 消</el-button>
          <el-button type="primary" @click="addAttackPathData"> 新 建 </el-button>
        </span>
           </template>
         </el-dialog>
       </div>
      </div>
    </el-dialog>
  </div>
</template>
<script lang="ts" setup>
import {onMounted, onUnmounted, reactive, ref, shallowReactive, watch} from 'vue';
import { emitter } from '@/utils/bus';
import { ElMessage } from 'element-plus/es';
import {
  getAttackPathApi,
  delAttackPathApi,
  addAttackPathApi,
  getSceneInstanceApi
} from '@/api/topo/topo';
import {
  attackPathList
} from '../defaultConfig';
import { ElMessageBox } from "element-plus";
import debounce from "lodash/debounce";
import TableComponent from "@/components/table/TableComponent.vue";

// 攻击路径表单
const attackPathForm = reactive({
  name: '',
  sourceInstanceUUID: '',
  targetInstanceUUID: ''
});

/**
 * 校验开始节点、结束节点不能一样
 * @param rule
 * @param value
 * @param callback
 */
const validateInstance = (rule, value, callback) => {
  if (value === '') {
    callback(new Error('请选择节点'));
  } else if (attackPathForm.sourceInstanceUUID === attackPathForm.targetInstanceUUID) {
    callback(new Error('开始节点和结束节点不能一样'));
  } else {
    callback();
  }
};

// 攻击路径表单规则
const attackPathRules = {
  name: [{ required: true, trigger: 'blur', message: '名称不能为空' }],
  sourceInstanceUUID: [{ validator: validateInstance, trigger: 'change', required: true }],
  targetInstanceUUID: [{ validator: validateInstance, trigger: 'change', required: true }],
};
const attackPathFormRef = ref(null);
const attackPathVisible = ref(false);
const visible = ref(false);

// 攻击路径
const tableRef = ref(null);
const pageInfo = ref(null);
const state = shallowReactive({
  tableData: [],
});
let sceneID = '';
const keyword = ref('');

// 场景实例列表
const sceneInstanceList = ref([]);

/**
 * 攻击路径（防抖）
 * @type {DebouncedFuncLeading<(function(): Promise<void>)|*> | DebouncedFunc<(function(): Promise<void>)|*>}
 */
const getAttackPathData = debounce(async() =>{
  const {
     data: { list, total, page, pageSize },
  } = await getAttackPathApi( sceneID, {
    page: pageInfo.value.page,
    pageSize: pageInfo.value.pageSize,
    keyword: keyword.value
  });
  state.tableData = list || [];
  if (tableRef.value) {
    tableRef.value.setPageInfo({ total, page, pageSize });
  }
}, import.meta.env.VITE_INPUT_DEBOUNCE_TIME);


// 初始化页数
const setDefaultPage = arg => (pageInfo.value = arg);
const setPageInfo = page => {
  pageInfo.value = page;
  getAttackPathData();
};

/**
 * 新建攻击路径（确定）
 */
const addAttackPathData = () =>{
  attackPathFormRef.value?.validate(async valid => {
    if (valid) {
      addAttackPathApi(sceneID, attackPathForm).then(res => {
        if (!(res instanceof Error)) {
          ElMessage.success('新建成功');
          attackPathVisible.value = false;
          getAttackPathData();
        }
      });
    }
  });
}

// 操作列配置
const optionsButton = [
  {
    link: true,
    type: 'primary',
    name: '测试',
    click: item => {
      ElMessageBox.prompt('持续时间（s）', '', {
        confirmButtonText: '确 定',
        cancelButtonText: '取 消',
        inputErrorMessage: '持续时间不能小于1s',
        dangerouslyUseHTMLString: true,
        center: true,
        customClass: 'attack-path-test',
        inputValidator: value => {
          return value > 0;
        },
      }).then(async ({ value }) => {
        if(value) {
          item.time = Number(value);
          let newWindow = window.open('#/layout/monitor/situation/defense', 'SituationDefenseOpen');
          sessionStorage.setItem('attackPath', JSON.stringify({ attackPath: JSON.stringify(item), sceneID: '场景-' + sceneID }))
          setTimeout(() =>{
            newWindow.postMessage({ attackPath: JSON.stringify(item), sceneID: '场景-' + sceneID }, '*');
          }, 100)
        }
      })
    }
  },
  {
    link: true,
    type: 'danger',
    name: '删除',
    click: item => {
      ElMessageBox.confirm(`攻击路径【${ item.name }】删除后将不可恢复！`, '删除攻击路径', {
        confirmButtonText: '删 除',
        cancelButtonText: '取 消',
        type: 'warning',
        center: true,
        customClass: 'delMessageBox',
        confirmButtonClass: 'delButtonClass',
      }).then(async () => {
        delAttackPathApi(sceneID, item.id).then(res => {
          if (!(res instanceof Error)) {
            ElMessage.success(`${res.msg}`);
            getAttackPathData();
          }
        });
      });
    },
  },
];

const attackPathShow = (attackPathList) =>{
  let path = '';
  attackPathList.forEach((item, index) =>{
    if(index !== attackPathList.length - 1) {
      path += `${item.name} -> `;
    } else {
      path +=  `${item.name}`;
    }
  })

  return path;
}

/**
 * 获取场景实例列表
 */
const getSceneInstanceList = () =>{
  getSceneInstanceApi(sceneID, { page: 1, pageSize: 9999}).then(res =>{
    sceneInstanceList.value = res.data?.list || [];
  })
}

/**
 * 攻击路径弹窗显示
 */
const sceneAttackPathDialogShow = (id) =>{
  visible.value = true;
  sceneID = id;
  getAttackPathData();
}

emitter.on('sceneAttackPathDialog', sceneAttackPathDialogShow);

// 监听弹窗显示、隐藏（隐藏刷新外层列表）
watch(attackPathVisible, cur => {
  if(cur) {
    getSceneInstanceList();
  } else {
    attackPathFormRef.value.resetFields();
  }
});

onMounted(() =>{

})

/**
 * 卸载-生命周期（主要处理清除定时器、解绑操作）
 */
onUnmounted(() => {
  emitter.off('sceneAttackPathDialog', sceneAttackPathDialogShow);
});
</script>
<style lang="scss" scoped>
.snapshot-button {
  margin-bottom: 12px;
}

.attack-path-search {
  width: 200px;
  float: right;
}

:deep(.attack-path-dialog) {
  width: 900px;

  .el-table {
    height: 460px!important;
  }

  .el-table__body-wrapper {
    height: 330px!important;
  }

  .el-empty__image {
    width: 108px!important;
  }
}

:deep(.add-attack-dialog) {
  width: 560px;
  .el-form {
    max-width: 460px;
    .el-form-item__label {
      width: 100px;
    }
  }
}
</style>
